/**
 * Copyright (C), 2011-2016 The Store
 * File Name: MessageSender.java
 * Encoding: UTF-8
 * Date: Feb 23, 2012
 * History: 
 */
package com.waynewan.qcomet.message;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.waynewan.qcomet.event.ConnectionHolder;
import com.waynewan.qcomet.listener.AbstractListener;

/**
 *
 * @author Wayne Wan(bestirwiny@gmail.com)
 * @version Revision: 1.00 Date: Feb 23, 2012
 */
public class MessageSender implements Runnable {
	//128 spaces
	public final static String PRELUDE_256B = "                                      " +
			"                                                                         " +
			"                                                                         " +
			"                                                                        ";
	private static Log log = LogFactory.getLog(MessageSender.class);
	private ConnectionHolder holder;
	private AbstractListener listener;
	private HttpServletResponse conn;
	private List<String> messages = new ArrayList<String>();
	private Lock lock = new ReentrantLock();
	private Condition cond = lock.newCondition();
	private boolean running = true;
	
	public MessageSender(HttpServletResponse conn, AbstractListener listener){
		this.conn = conn;
		this.listener = listener;
	}

	/**
     * Add message for sending.
     */
    public void send(String message) {
    	lock.lock();
    	try{
    		messages.add(message);
    		cond.signal();
    	}finally{
    		lock.unlock();
    	}
    }

    @Override
    public void run() {
    	while(running){
	    	lock.lock();
	    	PrintWriter writer = null;
	    	try{
	    		if(messages.size()<1){
	    			cond.await();
	    		}
	    		String[] pendingMessages = messages.toArray(new String[]{});
	    		messages.clear();
	    		writer = conn.getWriter();
	    		for (int j = 0; j < pendingMessages.length; j++) {
	            	log.debug("sending a message '" + pendingMessages[j] +"'" + " to" + conn.toString());
	                writer.println(PRELUDE_256B + pendingMessages[j] + "<br>");
	            }
	            writer.flush();
	    	} catch (IOException e) {
	        	writer = null;
	        	getListener().removeConn(getHolder().getClientId());
	        	log.error("io exception", e);
	        } catch (InterruptedException e) {
	        	writer = null;
	        	getListener().removeConn(getHolder().getClientId());
	        	log.error("interrupted exception", e);
			}finally{
	    		lock.unlock();
	    	}
    	}
    }
    
    public HttpServletResponse getConn() {
		return conn;
	}

	public void setConn(HttpServletResponse conn) {
		this.conn = conn;
	}
	
	public void stop(){
		this.running = false;
		lock.lock();
    	try{
    		cond.signal();
    	}finally{
    		lock.unlock();
    	}
	}

	@Override
	public int hashCode() {
		return conn.hashCode();
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		MessageSender other = (MessageSender) obj;
		if (conn == null) {
			if (other.conn != null)
				return false;
		} else if (!conn.equals(other.conn))
			return false;
		return true;
	}

	public ConnectionHolder getHolder() {
		return holder;
	}

	public void setHolder(ConnectionHolder holder) {
		this.holder = holder;
	}

	public AbstractListener getListener() {
		return listener;
	}

	public void setListener(AbstractListener listener) {
		this.listener = listener;
	}
}
